/**
 * 词法分析器
 *
 * 缺失的特性：
 * 1.不支持Unicode；
 * 2.不支持二进制、八进制、十六进制
 * 3.不支持转义
 * 4.字符串只支持双引号
 */

package mynl

import (
	"fmt"
)

//Token的类型
type TokenKind int

const (
	TokenKind_Keyword TokenKind = iota
	TokenKind_Identifier
	TokenKind_StringLiteral
	TokenKind_IntegerLiteral
	TokenKind_DecimalLiteral
	TokenKind_NullLiteral
	TokenKind_BooleanLiteral
	TokenKind_Seperator
	TokenKind_Operator
	TokenKind_EOF
)

func (selfx *TokenKind) String() string {
	var x = []string{"Keyword", "Identifier", "StringLiteral", "IntegerLiteral", "DecimalLiteral", "NullLiteral", "BooleanLiteral", "Seperator", "Operator", "EOF"}
	return x[*selfx]
}

// 代表一个Token的数据结构
type Token struct {
	Kind TokenKind
	Text string
}

func NewToken(Kind TokenKind, Text string) *Token {
	return &Token{
		Kind: Kind,
		Text: Text,
	}
}

/**
 * 一个字符串流。其操作为：
 * Peek():预读下一个字符，但不移动指针；
 * Next():读取下一个字符，并且移动指针；
 * eof():判断是否已经到了结尾。
 */
type CharStream struct {
	data string
	pos  int //当前读到的位置
	line int //行号
	col  int //列号
}

func NewCharStream(data string) *CharStream {
	return &CharStream{
		pos:  0,
		line: 1,
		col:  0,
		data: data,
	}
}

func (selfx *CharStream) Peek() string {
	if selfx.Eof() {
		return ""
	}

	return selfx.data[selfx.pos : selfx.pos+1]
}

func (selfx *CharStream) Next() string {
	if selfx.Eof() {
		return ""
	}

	selfx.pos++
	var ch = selfx.data[selfx.pos-1 : selfx.pos]
	if ch == "\n" {
		selfx.line++
		selfx.col = 0
	} else {
		selfx.col++
	}
	return ch
}

func (selfx *CharStream) Eof() bool {
	return selfx.pos >= len(selfx.data)
}

/**
 * 词法分析器
 * 语法分析器从这里获取Token。
 * 词法分析器的接口像是一个流，词法解析是按需进行的。
 * 支持下面两个操作：
 * Next(): 返回当前的Token，并移向下一个Token。
 * Peek(): 预读当前的Token，但不移动当前位置。
 * peek2(): 预读第二个Token，但不移动当前位置。
 */
type Scanner struct {
	tokens   []Token //采用一个array，能预存多个Token.
	stream   CharStream
	KeyWords map[string]bool
}

func NewScanner(stream CharStream) *Scanner {
	var KeyWords = make(map[string]bool)
	KeyWords["function"] = true
	KeyWords["class"] = true
	KeyWords["break"] = true
	KeyWords["delete"] = true
	KeyWords["return"] = true
	KeyWords["case"] = true
	KeyWords["do"] = true
	KeyWords["if"] = true
	KeyWords["switch"] = true
	KeyWords["var"] = true
	KeyWords["catch"] = true
	KeyWords["else"] = true
	KeyWords["in"] = true
	KeyWords["selfx"] = true
	KeyWords["void"] = true
	KeyWords["continue"] = true
	KeyWords["false"] = true
	KeyWords["instanceof"] = true
	KeyWords["throw"] = true
	KeyWords["while"] = true
	KeyWords["debugger"] = true
	KeyWords["finally"] = true
	KeyWords["new"] = true
	KeyWords["true"] = true
	KeyWords["with"] = true
	KeyWords["default"] = true
	KeyWords["for"] = true
	KeyWords["null"] = true
	KeyWords["try"] = true
	KeyWords["typeof"] = true
	//下面这些用于严格模式
	KeyWords["implements"] = true
	KeyWords["let"] = true
	KeyWords["private"] = true
	KeyWords["public"] = true
	KeyWords["yield"] = true
	KeyWords["interface"] = true
	KeyWords["package"] = true
	KeyWords["protected"] = true
	KeyWords["static"] = true

	return &Scanner{
		KeyWords: KeyWords,
		stream:   stream,
	}
}

func (selfx *Scanner) Next() *Token {
	var t *Token = nil
	if len(selfx.tokens) > 0 {
		t = &selfx.tokens[0]
		selfx.tokens = selfx.tokens[1:]
	} else {
		t = selfx.getAToken()
	}

	return t
}

func (selfx *Scanner) Peek() *Token {
	var t *Token = nil
	if len(selfx.tokens) > 0 {
		t = &selfx.tokens[0]

	} else {
		t = selfx.getAToken()
		selfx.tokens = append(selfx.tokens, *t)
	}
	return t
}

func (selfx *Scanner) Peek2() *Token {
	for {
		if len(selfx.tokens) >= 2 {
			break
		}
		selfx.tokens = append(selfx.tokens, *selfx.getAToken())
	}

	var t = &selfx.tokens[1]
	return t
}

//从字符串流中获取一个新Token。
func (selfx *Scanner) getAToken() *Token {
	selfx.skipWhiteSpaces()
	if selfx.stream.Eof() {
		//EOF
		return NewToken(TokenKind_EOF, "")
	} else {
		//预读一个Token
		var ch string = selfx.stream.Peek()
		if selfx.isLetter(ch) || ch == "_" {
			//标识符
			return selfx.parseIdentifer()
		} else if ch == "\"" {
			//字符串处理
			return selfx.parseStringLiteral()
		} else if ch == "(" || ch == ")" || ch == "{" || ch == "}" || ch == "[" || ch == "]" ||
			ch == "," || ch == ";" || ch == ":" || ch == "?" || ch == "@" {
			//分隔符处理，包括括号，花括号，方括号，逗号，分号，冒号，问好，@
			selfx.stream.Next()
			return NewToken(TokenKind_Seperator, ch)
		} else if selfx.isDigit(ch) {
			//解析数字字面量，语法是：
			// DecimalLiteral: IntegerLiteral '.' [0-9]*
			//   | '.' [0-9]+
			//   | IntegerLiteral
			//
			// IntegerLiteral: '0' | [1-9] [0-9]*
			selfx.stream.Next()
			var ch1 = selfx.stream.Peek()
			var literal string = ""

			//首先解析整数部分
			if ch == "0" {
				//暂不支持八进制、二进制、十六进制
				if !(ch1 >= "1" && ch1 <= "9") {
					literal = "0"
				} else {
					fmt.Println("0 cannot be followed by other digit now, at line: ", selfx.stream.line, " col: ", selfx.stream.col)
					//暂时先跳过去
					selfx.stream.Next()
					return selfx.getAToken()
				}
			} else if ch >= "1" && ch <= "9" {
				literal += ch
				for {
					if !selfx.isDigit(ch1) {
						break
					}
					ch = selfx.stream.Next()
					literal += ch
					ch1 = selfx.stream.Peek()
				}
			}
			//解析小数部分
			if ch1 == "." {
				//小数字面量
				literal += "."
				selfx.stream.Next()
				ch1 = selfx.stream.Peek()
				for {
					if !selfx.isDigit(ch1) {
						break
					}
					ch = selfx.stream.Next()
					literal += ch
					ch1 = selfx.stream.Peek()
				}
				return NewToken(TokenKind_DecimalLiteral, literal)
			} else {
				//返回一个整型直面量
				return NewToken(TokenKind_IntegerLiteral, literal)
			}
		} else if ch == "." {
			//解析以.开头的小数，要求后面至少有一个数字
			selfx.stream.Next()
			var ch1 = selfx.stream.Peek()
			if selfx.isDigit(ch1) {
				//小数字面量
				var literal = "."
				for {
					if !selfx.isDigit(ch1) {
						break
					}
					ch = selfx.stream.Next()
					literal += ch
					ch1 = selfx.stream.Peek()
				}
				return NewToken(TokenKind_DecimalLiteral, literal)
			} else if ch1 == "." {
				//...省略号
				selfx.stream.Next()
				//第三个.
				ch1 = selfx.stream.Peek()
				if ch1 == "." {
					return NewToken(TokenKind_Seperator, "...")
				} else {
					fmt.Println("Unrecognized pattern : .., missed a . ?")
					return selfx.getAToken()
				}
			} else {
				//.号分隔符
				return NewToken(TokenKind_Seperator, ".")
			}
		} else if ch == "/" {
			//操作符/、/=
			//单行注释符//
			//多行注释符/*
			selfx.stream.Next()
			var ch1 = selfx.stream.Peek()
			if ch1 == "*" {
				selfx.skipMultipleLineComments()
				return selfx.getAToken()
			} else if ch1 == "/" {
				selfx.skipSingleLineComment()
				return selfx.getAToken()
			} else if ch1 == "=" {
				selfx.stream.Next()
				return NewToken(TokenKind_Operator, "/=")
			} else {
				return NewToken(TokenKind_Operator, "/")
			}
		} else if ch == "+" {
			//操作符+、++、+=
			selfx.stream.Next()
			var ch1 = selfx.stream.Peek()
			if ch1 == "+" {
				selfx.stream.Next()
				return NewToken(TokenKind_Operator, "++")
			} else if ch1 == "=" {
				selfx.stream.Next()
				return NewToken(TokenKind_Operator, "+=")
			} else {
				return NewToken(TokenKind_Operator, "+")
			}
		} else if ch == "-" {
			//操作符-、--、-=
			selfx.stream.Next()
			var ch1 = selfx.stream.Peek()
			if ch1 == "-" {
				selfx.stream.Next()
				return NewToken(TokenKind_Operator, "--")
			} else if ch1 == "=" {
				selfx.stream.Next()
				return NewToken(TokenKind_Operator, "-=")
			} else {
				return NewToken(TokenKind_Operator, "-")
			}
		} else if ch == "*" {
			//操作符*、*=
			selfx.stream.Next()
			var ch1 = selfx.stream.Peek()
			if ch1 == "=" {
				selfx.stream.Next()
				return NewToken(TokenKind_Operator, "*=")
			} else {
				return NewToken(TokenKind_Operator, "*")
			}
		} else if ch == "%" {
			selfx.stream.Next()
			var ch1 = selfx.stream.Peek()
			if ch1 == "=" {
				selfx.stream.Next()
				return NewToken(TokenKind_Operator, "%=")
			} else {
				return NewToken(TokenKind_Operator, "%")
			}
		} else if ch == ">" {
			selfx.stream.Next()
			var ch1 = selfx.stream.Peek()
			if ch1 == "=" {
				selfx.stream.Next()
				return NewToken(TokenKind_Operator, ">=")
			} else if ch1 == ">" {
				selfx.stream.Next()
				var ch1 = selfx.stream.Peek()
				if ch1 == ">" {
					selfx.stream.Next()
					ch1 = selfx.stream.Peek()
					if ch1 == "=" {
						selfx.stream.Next()
						return NewToken(TokenKind_Operator, ">>>=")
					} else {
						return NewToken(TokenKind_Operator, ">>>")
					}
				} else if ch1 == "=" {
					selfx.stream.Next()
					return NewToken(TokenKind_Operator, ">>=")
				} else {
					return NewToken(TokenKind_Operator, ">>")
				}
			} else {
				return NewToken(TokenKind_Operator, ">")
			}
		} else if ch == "<" {
			selfx.stream.Next()
			var ch1 = selfx.stream.Peek()
			if ch1 == "=" {
				selfx.stream.Next()
				return NewToken(TokenKind_Operator, "<=")
			} else if ch1 == "<" {
				selfx.stream.Next()
				ch1 = selfx.stream.Peek()
				if ch1 == "=" {
					selfx.stream.Next()
					return NewToken(TokenKind_Operator, "<<=")
				} else {
					return NewToken(TokenKind_Operator, "<<")
				}
			} else {
				return NewToken(TokenKind_Operator, "<")
			}
		} else if ch == "=" {
			selfx.stream.Next()
			var ch1 = selfx.stream.Peek()
			if ch1 == "=" {
				selfx.stream.Next()
				var ch2 = selfx.stream.Peek()
				if ch2 == "=" {
					selfx.stream.Next()
					return NewToken(TokenKind_Operator, "===")
				} else {
					return NewToken(TokenKind_Operator, "==")
				}
			} else if ch1 == ">" {
				//箭头=>
				selfx.stream.Next()
				return NewToken(TokenKind_Operator, "=>")
			} else {
				return NewToken(TokenKind_Operator, "=")
			}
		} else if ch == "!" {
			selfx.stream.Next()
			var ch1 = selfx.stream.Peek()
			if ch1 == "=" {
				selfx.stream.Next()
				var ch2 = selfx.stream.Peek()
				if ch2 == "=" {
					selfx.stream.Next()
					return NewToken(TokenKind_Operator, "!==")
				} else {
					return NewToken(TokenKind_Operator, "!=")
				}
			} else {
				return NewToken(TokenKind_Operator, "!")
			}
		} else if ch == "|" {
			selfx.stream.Next()
			var ch1 = selfx.stream.Peek()
			if ch1 == "|" {
				selfx.stream.Next()
				return NewToken(TokenKind_Operator, "||")
			} else if ch1 == "=" {
				selfx.stream.Next()
				return NewToken(TokenKind_Operator, "|=")
			} else {
				return NewToken(TokenKind_Operator, "|")
			}
		} else if ch == "&" {
			selfx.stream.Next()
			var ch1 = selfx.stream.Peek()
			if ch1 == "&" {
				selfx.stream.Next()
				return NewToken(TokenKind_Operator, "&&")
			} else if ch1 == "=" {
				selfx.stream.Next()
				return NewToken(TokenKind_Operator, "&=")
			} else {
				return NewToken(TokenKind_Operator, "&")
			}
		} else if ch == "^" {
			selfx.stream.Next()
			var ch1 = selfx.stream.Peek()
			if ch1 == "=" {
				selfx.stream.Next()
				return NewToken(TokenKind_Operator, "^=")
			} else {
				return NewToken(TokenKind_Operator, "^")
			}
		} else if ch == "~" {
			selfx.stream.Next()
			return NewToken(TokenKind_Operator, ch)
		} else {
			if ch == "\n" || ch == "\r" {
				//换行符不处理
			} else {
				//暂时去掉不能识别的字符
				fmt.Println("Unrecognized pattern meeting ': ", ch, "', at", selfx.stream.line, " col: ", selfx.stream.col)
			}
			selfx.stream.Next()
			return selfx.getAToken()
		}
	}
}

/**
 * 跳过单行注释
 */
func (selfx *Scanner) skipSingleLineComment() {
	//跳过第二个/，第一个之前已经跳过去了。
	selfx.stream.Next()

	//往后一直找到回车或者eof
	for {
		if selfx.stream.Peek() == "\n" || selfx.stream.Eof() {
			break
		}
		selfx.stream.Next()
	}
}

/**
 * 跳过多行注释
 */
func (selfx *Scanner) skipMultipleLineComments() {
	//跳过*，/之前已经跳过去了。
	selfx.stream.Next()

	if !selfx.stream.Eof() {
		var ch1 = selfx.stream.Next()
		//往后一直找到回车或者eof
		for {
			if selfx.stream.Eof() {
				break
			}
			var ch2 = selfx.stream.Next()
			if ch1 == "*" && ch2 == "/" {
				return
			}
			ch1 = ch2
		}
	}

	//如果没有匹配上，报错。
	fmt.Println("Failed to find matching */ for multiple line comments at ': ", selfx.stream.line, " col: ", selfx.stream.col)
}

/**
 * 跳过空白字符
 */
func (selfx *Scanner) skipWhiteSpaces() {
	for {
		if !selfx.isWhiteSpace(selfx.stream.Peek()) {
			break
		}
		selfx.stream.Next()
	}
}

/**
 * 字符串字面量。
 * 目前只支持双引号，并且不支持转义。
 */
func (selfx *Scanner) parseStringLiteral() *Token {
	var token *Token = NewToken(TokenKind_StringLiteral, "")

	//第一个字符不用判断，因为在调用者那里已经判断过了
	selfx.stream.Next()

	//不断读取字符
	for {
		if selfx.stream.Eof() || selfx.stream.Peek() == "\"" {
			break
		}
		token.Text += selfx.stream.Next()
	}

	if selfx.stream.Peek() == "\"" {
		//消化掉字符换末尾的引号
		selfx.stream.Next()
	} else {
		//找不到结束的引号
		fmt.Println("Expecting an \" at line: ", selfx.stream.line, " col: ", selfx.stream.col)
	}

	return token
}

/**
 * 解析标识符。从标识符中还要挑出关键字。
 */
func (selfx *Scanner) parseIdentifer() *Token {
	var token *Token = NewToken(TokenKind_Identifier, "")

	//第一个字符不用判断，因为在调用者那里已经判断过了
	token.Text += selfx.stream.Next()

	//读入后序字符
	for {
		if selfx.stream.Eof() ||
			!selfx.isLetterDigitOrUnderScore(selfx.stream.Peek()) {
			break
		}
		token.Text += selfx.stream.Next()
	}

	//识别出关键字（从字典里查，速度会比较快），并进行处理
	_, ok := selfx.KeyWords[token.Text]
	if ok {
		token.Kind = TokenKind_Keyword
	} else if token.Text == "null" {
		//null
		token.Kind = TokenKind_NullLiteral
	} else if token.Text == "true" || token.Text == "false" {
		//布尔型字面量
		token.Kind = TokenKind_BooleanLiteral
	}

	return token
}

//字母、数字、下划线、点
func (selfx *Scanner) isLetterDigitOrUnderScore(ch string) bool {
	return (ch >= "A" && ch <= "Z" ||
		ch >= "a" && ch <= "z" ||
		ch >= "0" && ch <= "9" ||
		ch == "_" || ch == ".")
}

//字母
func (selfx *Scanner) isLetter(ch string) bool {
	return (ch >= "A" && ch <= "Z" || ch >= "a" && ch <= "z")
}

//数字
func (selfx *Scanner) isDigit(ch string) bool {
	return (ch >= "0" && ch <= "9")
}

//空格
func (selfx *Scanner) isWhiteSpace(ch string) bool {
	return (ch == " " || ch == "\t" || ch == "\n" || ch == "\r")
}
